#pragma once

#include "cmconstants.h"
#include "longinstance.h"
#include <vector>
#include <iostream>
using namespace std;


class Rectangle
{
private:
	Coordinate ul, lr;			//!<Upper-Left and Lower-Right coordinates
	vector<Coordinate> coos; 	//!<The vector holding all the coordinates that have the same neighborhood
	LongInstance longinstance; 	//!< This is the longinstance shared between all the coordinates in this rectangle

	/** This function inputs a coordinate and tells if there is a horizontal or vertical patt that starts from that
	 *  coordination and does not hit any point in this rectangle.
	 */
	emptyDirection emptyLine (const Coordinate& c) const;

	/** Returns true if this rectangle does not include any coordinate with the same row as of the given coordinate
	 */
	bool nothingOnRow (const Coordinate& c) const; 

	/** Returns true if this rectangle does not include any coordinate with the same col as of the given coordinate
	 */
	bool nothingOnCol (const Coordinate& c) const; 

public:
	Coordinate getUL(void) const {return ul;}	//!< Returns the coordinate of the upper left corner
	Coordinate getLR(void) const {return lr;}	//!< Returns the coordinate of the lower right corner
	Coordinate getCoo(int i) const {return this->coos[i];} //!< Returns the coordinate whose index is given. To be used in ruletangle2.
	int getUL_Row(void) const {return ul.row;}	//!< Return the row of the upper left corner
	int getUL_Col(void) const {return ul.col;}	//!< Return the col of the upper left corner
	int getLR_Row(void) const {return lr.row;}	//!< Return the row of the lower right corner
	int getLR_Col(void) const {return lr.col;}	//!< Return the col of the lower right corner
	int getTop(void) const {return ul.row;}	//!< Return the row of the upper left corner
	int getLeft(void) const {return ul.col;}	//!< Return the col of the upper left corner
	int getBottom(void) const {return lr.row;}	//!< Return the row of the lower right corner
	int getRight(void) const {return lr.col;}	//!< Return the col of the lower right corner
	int gettotalCoo (void) const {return coos.size();} //!< Returns the number of pixels in this rectangle
	LongInstance getLI (void) const {return longinstance;} //!< Returns the rectangle's longinstance 
	void setUL (const Coordinate& c) {ul.row = c.row; ul.col = c.col;}
	void setLR (const Coordinate& c) {lr.row = c.row; lr.col = c.col;}
	void setUL_Row (int r) {ul.row = r;}
	void setUL_Col (int c) {ul.col = c;}
	void setLR_Row (int r) {lr.row = r;}
	void setLR_Col (int c) {lr.col = c;}
	void setTop (int r) {ul.row = r;}
	void setLeft (int c) {ul.col = c;}
	void setBottom (int r) {lr.row = r;}
	void setRight (int c) {lr.col = c;}
	void clearCoos (void); //!< delete all the coordinates in the rectangle. Does not change the location of the corners.
	bool coversAnyCoo (const vector<Coordinate>& coos) const; //!< true if this object overlaps any of the given coos.
	int coveredCooNum (const vector<Coordinate>& coos) const; //!< true if this object overlaps any of the given coos.
	vector<Coordinate> getThoseCoosInsideOnly (const vector<Coordinate>& totalCoos) const;
	bool hasCooOnRow(int row) const;	//!< Returns true if this Rectangle has any of its coo on the given row
	bool hasCooOnCol(int col) const;	//!< Returns true if this Rectangle has any of its coo on the given col

	/**
	 * It returns a set of rectangles whose union has all the coos originally in this object, but does
	 * not geometrically cover any of the given coos.
	 */
	vector<Rectangle> breakRectangleToExcludeCoos (const vector<Coordinate>& coos) const;

	/**
	 * Returns two rectangles halfRect1 and halfRect2, whose union cover all the coos of this object, but geometrically 
	 * covers the minimum possible number of the given coos.
	 * Returns false if the given coo was too large to be computed.
	 */
	bool divideToTwoWithMinCooErrors (const vector<Coordinate>& coos, Rectangle& halfRect1, Rectangle& halfRect2, bool reportToConsole = false) const;

	/**
	 * Returns two rectangles halfRect1 and halfRect2, whose union cover all the coos of this object, but does not  
	 * geometrically cover the given coo.
	 * Returns false if this rectangle cannot be divided in such two rectangles.
	 */
	bool divideToTwoNotCoveringcoo (const Coordinate& coo, Rectangle& halfRect1, Rectangle& halfRect2) const;

	/**
	 * Returns the minimum growth required for a rectangle to include a coordinate. For example, a rectangle
	 * whose upper-left is (1,2), will need to grow 3 units to include the coordinate (0,0). The growth is always
	 * in the direction to the given coordinate. Returns 0 if the rectangle already includes the coordinate.
	 */
	int minDistance (const Coordinate& c) const;
	
	/** 
	 * \deprecated This function inputs a coordinate to exclude from its coordinates and
	 *  form new rectangles. Does not actually divide this rectangle but only
	 *  returns the number of resulted sub-rectangles if it is to be divided.
	 */
	int subRectNum (const Coordinate& c) const;

	/** This function inputs a coordinate inside the rectangle object, and divides this rectangle
	 *  into maximum 8 new rectangles so that the coordinates in each rectangle are all at on side of 
	 *  the given coordinate.  If there are less than 8 output rectangles, one or more of the output 
	 *  parameters will be empty rectangles (rX.coos.size()=0)
	 *
	 *	rTL rT rTR
	 *	rL  XX rR
	 *	rBL rB rBR
	 *
	 */
	void divide (const Coordinate& c, Rectangle& rT, Rectangle& rTR, Rectangle& rR, Rectangle& rBR,
		Rectangle& rB, Rectangle& rBL, Rectangle& rL, Rectangle& rTL) const;
	
	/** Adds a new pixel (coordinate) to this rectangle. Checks to see if the coo already exists.*/
	void addCoo (const Coordinate& c);

	/** Adds a new pixel (coordinate) to this rectangle. Does not checks to see if the coo already exists.*/
	void addCooNoCheck (const Coordinate& c);

	/** Creates a copy of this rectangle and adds the given coordinate to the copy. Returns the copy.*/
	Rectangle virtualExpand (const Coordinate& coo) const;

	/** Returns true if this rectangle includes the given coordinate in its pixel array, false otherwise. */
	bool hasCoo (const Coordinate& c) const;

	/** Returns the minimum ocleadian distance between the two rectangles. */
	float minDistance (const Rectangle& other) const;

	/** Returns true if the given rectangle overlaps or touches this rectangle. */
	bool overlaps (const Rectangle& other) const;

	/** Returns true if the given coordinate is geometrically located inside this rectangle. */
	bool cooIsInside (const Coordinate& c) const;

	/** Returns true if the given coordinate is at the left side of the left border of this rectangle. */
	bool cooIsOnLeft (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the right side of the right border of this rectangle. */
	bool cooIsOnRight (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the top of the top border of this rectangle. */
	bool cooIsOnTop (const Coordinate& coo) const;

	/** Returns true if the given coordinate is at the buttom of the buttom border of this rectangle. */
	bool cooIsOnButtom (const Coordinate& coo) const;

	/** Tells the relativelocation of a coordinate to this rectangle. */
	relativeLocation whichSideIs (const Coordinate& coo) const;

	//bool cooIsTopLeft (const Coordinate& coo) const;
	//bool cooIsTopRight (const Coordinate& coo) const;
	//bool cooIsButtomRight (const Coordinate& coo) const;
	//bool cooIsButtomLeft (const Coordinate& coo) const;

	/**
	 * Expands this object to the minimal rectangle that includes this rectangle and the other rectangle.
	 */
	void addRect (const Rectangle& other);

	void print (void) const;
	void printDetail (void) const;

	Rectangle() {}; //!< Constructor, creates an empty rectangle
	Rectangle (const Coordinate& coo); //!< Constructor, creates a singular rectangle (includes only the given coordiation)
	Rectangle (const Coordinate& coo, const LongInstance& li);
	Rectangle (const Coordinate& ul, const Coordinate& lr); //!< Constructor, creates an empty rectangle with the given coordinates
	Rectangle (const Coordinate& ul, const Coordinate& lr, const LongInstance& li); //!< Constructor
	Rectangle (const Rectangle& other); //!< Copy constructor
	Rectangle& operator= (const Rectangle& other);
	Rectangle(const vector<Coordinate>& coos);
	Rectangle (/*const vector<Coordinate>& coo, we dont need this, li has it*/ const LongInstance* li); //!< Creates the smallest rectangle that covers all the given coordinates.
	~Rectangle (void) {}; //!< Decunstructor
};
